#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/power_supply.h>
//#include <linux/video_output.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/jiffies.h>
#include <linux/miscdevice.h>
//#include <asm/bootinfo.h>
#include <linux/module.h>
#include <linux/device.h>
#include <ec_it8528.h>

#define LPC_EC_INDEX_PORT 0x2E
#define LPC_EC_DATA_PORT 0x2F

#define SIO_CONFIG_CTRL       0x02
#define SIO_CONFIG_PORT       0x2E

#define VOID       void
#define UINT8       unsigned char
#define UINT16       unsigned short

//#define linux_outb outb
//#define linux_inb inb

unsigned char linux_inb(unsigned short int port);
void linux_outb( unsigned short int port, unsigned char value);

unsigned char linux_inb(unsigned short int port)
{
  return inb(port);
}
void linux_outb( unsigned short int port, unsigned char value)
{
  outb(value,port);
}



#define BIT1 0x02

static ssize_t ecram_drv_config(unsigned char *ecram_vals);
static struct class  *ecram_drv_class;
static struct device *ecram_drv_class_dev;


static int ecram_drv_open(struct inode *inode, struct file *file)
{
	return 0;
}

ssize_t ecram_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	unsigned char ecram_vals[256];
	unsigned int i;
#if 0
	for(i = 0; i < 256;i++)
	{
		ecram_vals[i] = it8528_read(i);
	}
#endif
	memset(ecram_vals, 0xFF, sizeof(ecram_vals));
	ecram_drv_config(&ecram_vals[0]);

	copy_to_user(buf, ecram_vals, sizeof(ecram_vals));

	return sizeof(ecram_vals);
}

static ssize_t ecram_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
	int val;	

	copy_from_user(&val, buf, count);

	it8528_write((val>>8)&0xff , val&0xff);
	
	return 0;
}


static VOID
EnterConfigMode (
VOID
  )
/*++

Routine Description:
  Enter Super IO Config Mode.

Arguments:

Returns:
  None

--*/  
{
  UINT8  PnpKey;

  PnpKey = 0x87;
  linux_outb(SIO_CONFIG_PORT, PnpKey);
  PnpKey = 0x01;
  linux_outb(SIO_CONFIG_PORT, PnpKey);
  PnpKey = 0x55;
  linux_outb(SIO_CONFIG_PORT, PnpKey);
  PnpKey = 0x55;
  linux_outb(SIO_CONFIG_PORT, PnpKey);
  
  return;
}

static VOID
ExitConfigMode (
  VOID
  )
/*++

Routine Description:
  Exit Super IO Config Mode.

Arguments:

Returns:
  None

--*/    
{
  UINT8  RegData = 0x00;

  linux_outb (LPC_EC_INDEX_PORT, SIO_CONFIG_CTRL);
  RegData = linux_inb (LPC_EC_DATA_PORT) | BIT1;
  linux_outb (LPC_EC_INDEX_PORT, SIO_CONFIG_CTRL);  
  linux_outb (LPC_EC_DATA_PORT, RegData);
  
  return;
}

static ssize_t ecram_drv_config(unsigned char *ecram_vals)
{
	unsigned char Chipid0,Chipid1 =0;
	UINT16  DataTemp;
  EnterConfigMode();
  EnterConfigMode();
  linux_outb (LPC_EC_INDEX_PORT, 0x20);  
  Chipid0 = linux_inb (LPC_EC_DATA_PORT);
  ecram_vals[0]=Chipid0;
  linux_outb (LPC_EC_INDEX_PORT, 0x21);  
  Chipid1 = linux_inb (LPC_EC_DATA_PORT); 
  ecram_vals[1]=Chipid1;
  //DEBUG((EFI_D_ERROR, "Lyang: In Ls7a.c, line %d. Chipid0 %x Chipid1 %x\n", __LINE__,Chipid0,Chipid1));
  linux_outb (LPC_EC_INDEX_PORT, 0x7);  
  linux_outb (LPC_EC_DATA_PORT, 0x7);  
  linux_outb (LPC_EC_INDEX_PORT, 0x62); 
  linux_outb (LPC_EC_DATA_PORT, 0x04);  
  linux_outb (LPC_EC_INDEX_PORT, 0x63); 
  linux_outb (LPC_EC_DATA_PORT, 0x00); 
  linux_outb (LPC_EC_INDEX_PORT, 0x27);  
  DataTemp = linux_inb (LPC_EC_DATA_PORT);
  ecram_vals[2]=DataTemp;
  //DEBUG((EFI_D_ERROR, "Lyang: In EncryDriverPei.c, line %d.Data0 0x%x \n", __LINE__,Data0));
  linux_outb (LPC_EC_INDEX_PORT, 0x27);  
  linux_outb (LPC_EC_DATA_PORT, DataTemp|0x38); 
  linux_outb (LPC_EC_INDEX_PORT, 0xC2); 
  DataTemp = linux_inb (LPC_EC_DATA_PORT);
  ecram_vals[3]=DataTemp;
  //DEBUG((EFI_D_ERROR, "Lyang: In EncryDriverPei.c, line %d.Data0 0x%x \n", __LINE__,Data0));
  linux_outb (LPC_EC_INDEX_PORT, 0xC2);  
  linux_outb (LPC_EC_DATA_PORT, DataTemp|0x08);  
  linux_outb (LPC_EC_INDEX_PORT, 0xCA); 
  DataTemp = linux_inb (LPC_EC_DATA_PORT);
  ecram_vals[4]=DataTemp;
  //DEBUG((EFI_D_ERROR, "Lyang: In EncryDriverPei.c, line %d.Data1 0x%x \n", __LINE__,Data1));
//Output settings
  linux_outb (LPC_EC_INDEX_PORT, 0xCA);  
  linux_outb (LPC_EC_DATA_PORT, DataTemp|0x08);  
  DataTemp = linux_inb(0x402);
  ecram_vals[5]=DataTemp;
  printk("%02X \n",DataTemp);
  linux_outb (0x402, (DataTemp | 0x08));
  ExitConfigMode();	
  return 0;
}

static struct file_operations ecram_drv_fops = {
    .owner  =   THIS_MODULE,    /* ����һ���꣬�������ģ��ʱ�Զ�������__this_module���� */
    .open   =   ecram_drv_open,     
	.read	=	ecram_drv_read,	  
	.write	=	ecram_drv_write,	
};


int major;
static int ecram_drv_init(void)
{
	major = register_chrdev(0, "ecram_drv", &ecram_drv_fops); // ע��, �����ں�

	ecram_drv_class = class_create(THIS_MODULE, "ecramdrv");

	ecram_drv_class_dev = device_create(ecram_drv_class, NULL, MKDEV(major, 0), NULL, "ecram"); /* /dev/ecram*/


	return 0;
}

static void ecram_drv_exit(void)
{
	unregister_chrdev(major, "ecram_drv");
	device_unregister(ecram_drv_class_dev);
	class_destroy(ecram_drv_class);
}


module_init(ecram_drv_init);

module_exit(ecram_drv_exit);

MODULE_LICENSE("GPL");

